#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>


#include "../ScarletBaseCode/LoginMsgDefine.h"

using namespace std;

#define REV_BUF_SIZE 65535
#define SEND_BUF_SIZE 65535

#define MAX_CONNECTION 1000
#define MAX_EVENT_COUNT 1000

int main( int argc , char **argv )
{
	printf("epoll server begin!\n");
	int i,listenfd,epfd,nfds,connfd,sockfd;
	int portnumber = 12345;
	char serverip[20] = {"127.0.0.1"};
	size_t n;
	char revbuf[REV_BUF_SIZE] = {0};
	char sendbuf[SEND_BUF_SIZE] = {0};
	socklen_t clilen;

	struct epoll_event evlisten;
	struct epoll_event evlist[MAX_EVENT_COUNT];
	epfd=epoll_create(MAX_CONNECTION);
	struct sockaddr_in clientaddr,serveraddr;
	listenfd = socket( AF_INET , SOCK_STREAM , 0 );
	evlisten.data.fd = listenfd;
	evlisten.events = EPOLLIN;//SET TO LT NOT ET
	epoll_ctl( epfd , EPOLL_CTL_ADD , listenfd, &evlisten );
	memset( &clientaddr , 0 ,sizeof(clientaddr) );
	memset( &serveraddr , 0 ,sizeof(serveraddr) );
	serveraddr.sin_family = AF_INET;
	char localip[20] = {"127.0.0.1"};
	inet_aton( localip,&(serveraddr.sin_addr) );
	serveraddr.sin_port = htons(portnumber);
	bind( listenfd ,(sockaddr *)&serveraddr , sizeof(serveraddr));
	listen( listenfd , 50 );
	time_t begintime = time(NULL);
	while ( 1 )
	{
		time_t currenttime = time(NULL);
		if ( currenttime - begintime > 1 )
		{
			printf("running!\n");
			begintime = time(NULL);
		}
		nfds = epoll_wait( epfd , evlist , MAX_EVENT_COUNT , 0  );
		for ( int i = 0 ; i < nfds ; i++ )
		{
			// new connect
			if ( evlist[i].data.fd == listenfd )
			{
				connfd = accept( listenfd , (sockaddr *)&clientaddr , &clilen );
				if ( connfd < 0 )
				{
					printf("conndf = %d incorrect\n",connfd);
					return -1;
				}
				char *temp = inet_ntoa( clientaddr.sin_addr );
				printf("accept client connection from %s\n",temp);
				//set socket non block
				int iFlags;
				iFlags = fcntl( connfd, F_GETFL, 0 );
				iFlags |= O_NONBLOCK;
				iFlags |= O_NDELAY;
				fcntl( connfd, F_SETFL, iFlags );
				struct epoll_event ev;
				ev.data.fd = connfd;
				ev.events = EPOLLIN | EPOLLET;//SET TO LT NOT ET
				epoll_ctl( epfd , EPOLL_CTL_ADD , connfd , &ev );
				memset( &clientaddr , 0 , sizeof(clientaddr) );		
			}
			//REV MSG
			else if ( evlist[i].events & EPOLLIN )
			{
				sockfd = evlist[i].data.fd;
				printf("event number:%d fd:%d, REV MSG!\n",i,sockfd);

				if ( sockfd < 0 )
				{
					printf("sockfd REV %d\n",sockfd);
					continue;
				}
				//get all msg for this socket
				int iRet = 0 ;
				int bf_offset = 0;
				while( 0 != (iRet = read( sockfd , &revbuf[bf_offset] , 1024 ))  )
				{
					if( iRet < 0 )
					{
						if ( errno != EAGAIN )
						{
							printf("read sockfd %d error iRet =%d, errno:%d, reason:%s\n",sockfd,iRet,errno,strerror(errno));
							close(sockfd);
						}
						break;
					}
					bf_offset += 1024;
					printf("read sockfd %d :%d bytes\n",sockfd,iRet);

				}
				ScarletMsg *myrevmsg = (ScarletMsg*)revbuf;
				printf("msgid:%d msglen:%d\n",myrevmsg->MsgID , myrevmsg->MsgLen);
				unsigned short MsgID = myrevmsg->MsgID;
				switch ( MsgID )
				{
					case USER_LOGIN_REQUEST:
					{
						UserLoginRequest *msg = (UserLoginRequest*)myrevmsg;
						printf("username:%s \npassword:%s \n",msg->UserAccount , msg->UserPassword); 	
					}break;
					default:
					{
						printf("undefine msgid :%d\n",MsgID);
					}break;
				}
				evlist[i].events = EPOLLET;
				epoll_ctl(epfd, EPOLL_CTL_MOD , sockfd, &evlist[i]);	
				sleep(1);
			}
			//SEND MSG
			else if ( evlist[i].events & EPOLLOUT )
			{
				
				sockfd = evlist[i].data.fd;
				memset(&sendbuf , 0 ,sizeof(sendbuf) );
				write(sockfd, sendbuf , sizeof(sendbuf) );
				evlisten.data.fd = sockfd;
				evlisten.events = EPOLLIN;
				epoll_ctl( epfd , EPOLL_CTL_MOD , sockfd ,&evlisten);
				printf("sock :%d i:%d END TO!\n",sockfd , i);
				sleep(1);
			}
		}		



	}
	return 0;
}
